package com.cyru.statemachine.core.impl;

import com.cyru.statemachine.Visitor;
import com.cyru.statemachine.core.State;
import com.cyru.statemachine.core.StateMachine;
import com.cyru.statemachine.core.StateMachineConfiguration;
import com.cyru.statemachine.core.Transition;
import com.cyru.statemachine.core.exception.StateMachineNotReadyException;
import com.cyru.statemachine.core.exception.StateNotFoundException;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * description:
 *
 * @author zhangxuchuan
 * date 2022/5/1
 */
public class StateMachineImpl<S, E, C> implements StateMachine<S, E, C> {

    private String id;

    private final States<S, E, C> states;

    private StateMachineConfiguration<S, E, C> stateMachineConfiguration;

    private boolean ok;

    public StateMachineImpl(States<S, E, C> states, StateMachineConfiguration<S, E, C> stateMachineConfiguration) {
        this.ok = false;
        this.states = states;
        this.stateMachineConfiguration = stateMachineConfiguration;
    }

    public void ok() {
        this.ok = true;
    }

    public void isOk() {
        if (!ok) {
            throw new StateMachineNotReadyException("statemachine is not ready");
        }
    }

    @Override
    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void setConfiguration(StateMachineConfiguration<S, E, C> configuration) {
        this.stateMachineConfiguration = configuration;
    }

    @Override
    public StateMachineConfiguration<S, E, C> getConfiguration() {
        return this.stateMachineConfiguration;
    }

    @Override
    public S fireEvent(S source, E event, C context) {
        isOk();
        State<S, E, C> state = states.getState(source);
        if (state == null) {
            throw new StateNotFoundException("Source " + source + " not found");
        }
        // 一个状态根据某个状态可能会有多个转换结果
        List<Transition<S, E, C>> transitionList = state.getTransitionByEvent(event);
        if (CollectionUtils.isEmpty(transitionList)) {
            return null;
        }
        for (Transition<S, E, C> transition : transitionList) {
            // 校验当前转换是否满足场景
            if (!transition.check(context)) {
                continue;
            }
            return transition.execute(context).getId();
        }
        return null;
    }

    @Override
    public String accept(Visitor visitor) {
        StringBuffer sb = new StringBuffer();
        sb.append(visitor.visitOnEntry(this)).append(Visitor.newLine);

        for (State<S, E, C> state : states.getStates()) {
            sb.append(state.accept(visitor));
        }
        sb.append(visitor.visitOnExsit(this)).append(Visitor.newLine);
        return sb.toString();
    }
}
